#pragma once
#include <d3dx9.h>

//--------------------------------------------------------------------------------------------------------------
//Vertex Structures
//--------------------------------------------------------------------------------------------------------------
struct VTX_POSITION
{
	D3DXVECTOR3 Position;
};
struct VTX_POSITION_NORMAL
{
	D3DXVECTOR3 Position;
	D3DXVECTOR3 Normal;
};
struct VTX_POSITION_NORMAL_TEX
{
	D3DXVECTOR3 Position;
	D3DXVECTOR3 Normal;
	D3DXVECTOR2 TexCoord;
};

//--------------------------------------------------------------------------------------------------------------
//Math(Geometry) Classes
//--------------------------------------------------------------------------------------------------------------

class Vec3 : public D3DXVECTOR3
{
public:
	Vec3() {};
	Vec3(const float x, const float y, const float z) : D3DXVECTOR3(x,y,z){}
	Vec3(D3DXVECTOR3 &vec) : D3DXVECTOR3(vec){};

	Vec3 operator*(const Vec3& vec)
	{
		Vec3 output;
		output.x = vec.x * x;
		output.y = vec.y * y;
		output.z = vec.z * z;
		return output;
	}
	Vec3 operator*(const float k)
	{
		Vec3 output(*this);
		output.x *= k;
		output.y *= k;
		output.z *= k;
		return output;
	}
	Vec3 operator- (const float k) // Most useful thing ever
	{
		Vec3 output(*this);
		Vec3 normal(output.Normalized() * k);
		output.x -= normal.x ;
		output.y -= normal.y;
		output.z -= normal.z;
		return (output);
	}
	Vec3 operator - (const int k) // Most useful thing ever
	{
		return *this - (const float)k;
	}
	Vec3 operator+(float k)
	{
		Vec3 output(*this);
		Vec3 normal(output.Normalized() * k);
		output.x += normal.x;
		output.y += normal.y;
		output.z += normal.z;
		return output;
	}
	Vec3 operator+(int k)
	{
		return *this + (float)k;
	}
	Vec3 operator/(float k)
	{
		Vec3 output(*this);
		output.x /= k;
		output.y /= k;
		output.z /= k;
		return output;
	}
	Vec3 operator/(int k)
	{
		return *this / (float)k;
	}
	Vec3 operator+(const Vec3 &v) const
	{
		Vec3 output;
		output.x = x + v.x;
		output.y = y + v.y;
		output.z = z + v.z;
		return output;
	}
	Vec3 operator-(const Vec3 &v)
	{
		Vec3 output;
		output.x = x - v.x;
		output.y = y - v.y;
		output.z = z - v.z;
		return output;
	}
	~Vec3() {};
	float GetLength()
	{
		return sqrt(x*x + y*y + z*z);
	}
	float GetLenght()
	{
		return sqrt(x*x + y*y + z*z);
	}
	void Normalize()
	{
		*this /= GetLenght();
	}
	Vec3 Normalized()
	{	
		Vec3 output(*this);
		output /= GetLenght();
		return output;
	}
};



class Vec4 : public D3DXVECTOR4
{
public:
	Vec4() {};
	Vec4(const float x, const float y, const float z, const float w = 1.0f) : D3DXVECTOR4(x,y,z,w){}
	Vec4(const Vec4& v) : D3DXVECTOR4(v) {}
	Vec4(const Vec3& v) : D3DXVECTOR4(v.x, v.y, v.z, 1.0f) {}
	~Vec4() {};

};
class Mat4x4 : public D3DXMATRIX
{
public:
	Mat4x4(bool GenerateIdentity = false) : D3DXMATRIX() {
		if(GenerateIdentity)
		{
			D3DXMatrixIdentity(this);
		}	
	};
	Mat4x4(const D3DXMATRIX & mtx) : D3DXMATRIX(mtx) { }
	
	~Mat4x4() {};

	void SetPosition(Vec3 const &pos);
	void SetPosition(Vec4 const &pos);
	void SetLookAt(Vec3 target);

	Vec3 GetForward() const;
	Vec3 GetPosition() const;
	Vec4 Xform(const Vec4 &v) const;
	Vec3 Xform(const Vec3 &v) const;
	Mat4x4 Inverse() const;
	void RotateX(const float radians);
	void RotateY(const float radians);
	void RotateZ(const float radians);
	void RotateXYZ(const float x, const float y, const float z);

	static Mat4x4 g_Identity;
	
	// Initialization methods
	void BuildTranslation(const Vec3 &pos);
	void BuildTranslation(const float x, const float y, const float z );
	void BuildRotationX(const float radians);
	void BuildRotationY(const float radians);
	void BuildRotationZ(const float radians);
	void BuildRotationXYZ(const float y, const float x, const float z);
};



class Quaternion : public D3DXQUATERNION
{
public:
	Quaternion() : D3DXQUATERNION() { }
	Quaternion(float x, float y, float z, float w) : D3DXQUATERNION(x,y,z,w) {}
	~Quaternion() {}
};